﻿using Castle.DynamicProxy;
using HelperCommon.AOP.RedisCache;
using HelperCommon.Helper;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace HelperCommon.AOP
{
    public class RedisAOP : IInterceptor
    {
        protected readonly IRedisCaching redis; 

        public RedisAOP(IRedisCaching _redis)
        {
            this.redis = _redis;
        }
        public void Intercept(IInvocation invocation)
        {
            //
            //获取自定义缓存键
            var cacheKey = CustomCacheKey(invocation);
            //根据key获取相应的缓存值
            var cacheValue = redis.GetValue(cacheKey);
            if (cacheValue != null)
            {
                //将当前获取到的缓存值，赋值给当前执行方法
                invocation.ReturnValue = cacheValue;
                return;
            }
            //去执行当前的方法
            invocation.Proceed();
            //存入缓存
            if (!string.IsNullOrWhiteSpace(cacheKey))
            {
                redis.Set(cacheKey, invocation.ReturnValue,TimeSpan.FromSeconds(900));
            }
        }

        /// <summary>
        /// object 转 string
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected static string GetArgumentValue(object arg)
        {
            if (arg is DateTime || arg is DateTime?)
            {
                return ((DateTime)arg).ToString("yyyyMMddHHmmss");
            }

            if (arg is string || arg is ValueType || arg is Nullable)
            {
                return arg.ToString();
            }

            if (arg != null)
            {
                if (arg.GetType().IsClass)
                {
                    return MD5Helper.MD5Encrypt16(JsonSerializer.Serialize(arg));
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// 自定义缓存的key
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        protected string CustomCacheKey(IInvocation invocation)
        {
            var typeName = invocation.TargetType.Name;
            var methodName = invocation.Method.Name;
            var methodArguments = invocation.Arguments.Select(GetArgumentValue).Take(3).ToList();//获取参数列表，最多三个

            string key = $"{typeName}:{methodName}:";
            foreach (var param in methodArguments)
            {
                key = $"{key}{param}:";
            }
            return key.TrimEnd(':');
        }
    }
}
